//
// The resource management layer has been upgraded, thus deprecating this file.
//
#error *** hashtabl.cpp has been deprecated. ***

#include <stdlib.h>
#include <string.h>

#include "lib.h"
#include "hashtabl.h"

#if defined(DEBUG_CRESENTRY)
#  include "resfile.h"
#  include "resentry.h"
#endif


//----------------------------------------------------------------------------
// CHashTable stuff.

pCHashTable
newCHashTable(uint32 NumEntries, CHashTableDeleteFunc DeleteFunc, 
				void * UserData, CHashTableHashFunc HashFunc)
{
	pCHashTable hashtable;
	uint32		tablesize;


	// 'minus 1' because we already allocated one entry in the struct.
	tablesize = (NumEntries - 1) * sizeof(pCHashTableEntry);
	hashtable = (pCHashTable)calloc(sizeof(CHashTable) + tablesize, 1);

	if (hashtable)
		CHashTableConstruct(hashtable, NumEntries, DeleteFunc, UserData, 
			HashFunc);

	return hashtable;
}


void
deleteCHashTable(pCHashTable This)
{
	if (This)
	{
		CHashTableDestruct(This);
		free(This);
	}
}


void
CHashTableConstruct(pCHashTable This, uint32 NumEntries,
				CHashTableDeleteFunc DeleteFunc, void * UserData,
				CHashTableHashFunc HashFunc)
{
	if (This)
	{
		This->cTableSize	= NumEntries;
		This->cDeleteFunc	= DeleteFunc;
		This->cUserData		= UserData;

		This->cHashFunc = (HashFunc==NULL) ? CHashTableHashFunction : HashFunc;

		// CHashTableIterate overhead...
		This->cIterateIndex = 0;
		This->cIterateNext	= NULL;
	}
}


void
CHashTableDestruct(pCHashTable This)
{
	CHashTableFlush(This);
}


void
CHashTableIterateTable(pCHashTable This, CHashTableIterateFunc IterateFunc)
{
	if (This && IterateFunc)
	{
		pCHashTableEntry	ptr, nextptr;
		uint32				loop;

		for (loop = 0; loop < This->cTableSize; loop++)
		{
			ptr = This->cTable[loop];

			while (ptr)
			{
				// Save off 'next' pointer just incase...
				nextptr = ptr->cNext;

				IterateFunc(This, ptr->cData, This->cUserData);

				ptr = nextptr;
			}
		}
	}
}


void *
CHashTableIterate(pCHashTable This, bool8 Reset)
{
	void *	data = NULL;

	if (This)
	{
		if (Reset == true)
		{
			This->cIterateIndex = 0;
			This->cIterateNext  = NULL;
			return NULL;
		}

		while ((This->cIterateNext == NULL) && 
			(This->cIterateIndex < CHashTableTableSize(This)))
		{
			This->cIterateNext = This->cTable[This->cIterateIndex++];
		}

		if (This->cIterateNext)
		{
			data = CHashTableEntryData(This->cIterateNext);
			This->cIterateNext = CHashTableEntryNext(This->cIterateNext);
		}
	}

	return data;
}


pCHashTable
CHashTableResizeTable(pCHashTable This, uint32 NewSize)
{
	NOTUSED(NewSize);

	return This;
}

void
CHashTableFlush(pCHashTable This)
{
	if (This)
	{
		pCHashTableEntry	ptr, nextptr;
		uint32				loop;

		for (loop = 0; loop < This->cTableSize; loop++)
		{
			ptr = This->cTable[loop];

			while (ptr)
			{
				// Save off 'next' pointer just incase...
				nextptr = ptr->cNext;

				if (This->cDeleteFunc)
					This->cDeleteFunc(This, ptr->cData, This->cUserData);

				deleteCHashTableEntry(ptr);
				ptr = nextptr;
			}

			This->cTable[loop] = (pCHashTableEntry)0;
		}
	}
}

bool8
CHashTableAddDataByName(pCHashTable This, char * Name, void * Data)
{
	return CHashTableAddDataByID(This, This->cHashFunc(Name), Data);	
}


bool8
CHashTableAddDataByID(pCHashTable This, uint32 ID, void * Data)
{
	pCHashTableEntry entry = newCHashTableEntry(ID, Data);

	if (entry)
		return CHashTableAddEntry(This, entry);

	return false;
}


void
CHashTableRemoveDataByName(pCHashTable This, char * Name)
{
	CHashTableRemoveDataByID(This, This->cHashFunc(Name));	
}


void
CHashTableRemoveDataByID(pCHashTable This, uint32 ID)
{
	CHashTableRemoveEntry(This, ID);
}


void *
CHashTableGetDataByName(pCHashTable This, char * Name)
{
	return CHashTableGetDataByID(This, This->cHashFunc(Name));
}


void *
CHashTableGetDataByID(pCHashTable This, uint32 ID)
{
	pCHashTableEntry	ptr = CHashTableGetEntry(This, ID);

	if (ptr)
		return (ptr->cData);

	return NULL;
}


bool8
CHashTableAddEntry(pCHashTable This, pCHashTableEntry Entry)
{
	pCHashTableEntry	tentry;
	uint32				index = Entry->cHashID % This->cTableSize;


	// Make sure we don't add duplicate IDs to the table (all hell breaks
	//      loose if we do.
	if ((tentry = CHashTableGetEntry(This, Entry->cHashID)) != NULL)
	{
#if defined(DEBUG_CRESENTRY)
		DEBUGMSG(("CHashTableAddEntry(): Duplicate IDs found!"
			"    %s  <-->  %s",
				CResEntryName((pCResEntry)CHashTableEntryData(Entry)),
				CResEntryName((pCResEntry)CHashTableEntryData(tentry))));
#else
		DEBUGMSG(("CHashTableAddEntry(): Duplicate IDs found!"));
#endif
		return false;
	}

	Entry->cNext = This->cTable[index];
	This->cTable[index] = Entry;

	return true;
}


void
CHashTableRemoveEntry(pCHashTable This, uint32 ID)
{
	uint32				index = ID % This->cTableSize;
	pCHashTableEntry	ptr, prevptr;

	ptr		= This->cTable[index];
	prevptr	= NULL;

	while (ptr)
	{
		if (ptr->cHashID == ID)
			break;

		prevptr	= ptr;
		ptr		= ptr->cNext;
	}

	if (ptr)
	{
		if (prevptr)
			prevptr->cNext = ptr->cNext;
		else
			This->cTable[index] = ptr->cNext;

		deleteCHashTableEntry(ptr);
	}
}


pCHashTableEntry
CHashTableGetEntry(pCHashTable This, uint32 ID)
{
	uint32				index = ID % This->cTableSize;
	pCHashTableEntry	ptr;

	ptr = This->cTable[index];

	while (ptr)
	{
		if (ptr->cHashID == ID)
			break;

		ptr = ptr->cNext;
	}

	return ptr;
}


//----------------------------------------------------------------------------
//
//
uint32
CHashTableHashFunction(char * IDString)
{
	unsigned long	hashID = 0;
	unsigned long	crap;
	char *			ptr = IDString;


// REVISIT:  We should have the paths already stripped off!
	// Make sure it is lowercase and strip off the leading path...
	strlwr(IDString);
	ptr = strrchr(IDString, '\\');
	if (ptr)
		ptr++;
	else
		ptr = IDString;

	while (*ptr)
	{
		if ((crap = (hashID & 0xf0000000)) != 0)
		{
			hashID ^= crap >> 24;
			hashID &= ~crap;
		}

		hashID = (hashID << 4) + *ptr++;
	}

	return hashID;
}





//----------------------------------------------------------------------------
// CHashTableEntry stuff.
pCHashTableEntry
newCHashTableEntry(uint32 ID, void * Data)
{
	pCHashTableEntry hashentry = 
			(CHashTableEntry *)malloc(sizeof(CHashTableEntry));

	if (hashentry)
		CHashTableEntryConstruct(hashentry, ID, Data);

	return hashentry;
}


void
deleteCHashTableEntry(pCHashTableEntry This)
{
	if (This)
	{
		CHashTableEntryDestruct(This);
		free(This);
	}
}


void
CHashTableEntryConstruct(pCHashTableEntry This, uint32 ID, void * Data)
{
	if (This)
	{
		This->cHashID	= ID;
		This->cData		= Data;
		This->cNext		= NULL;
	}
}


void
CHashTableEntryDestruct(pCHashTableEntry This)
{
	if (This)
	{
	}
}
